// chanscan utilizes a ring to implement a 'wheel':
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

type mydat struct {
	d time.Time
	n int
}

var values ring.Ring
var wg sync.WaitGroup

const ringSize = 10

// Add replaces the next ring element with a new value
func Add(vals ring.Ring, dat mydat) {
	wg.Wait()
	vals.Next().Value = dat
}

// Scan gets all the values from the value ring and stores them
// for later use. Other go routines that manipulate the ring should
// wait for the waitgroup this function increments.
func Scan(vals ring.Ring) {
	wg.Add(1)
	defer wg.Done()

	l := vals.Len()
	for k := 0; k < l; k++ {
		v := vals.Next().Value
		// TODO use v
		fmt.Print(v.n, " ")
	}
	fmt.Println("")
}

// regularAdd adds a value to the value ring at regular time
// intervals.
func regularAdd(vals ring.Ring) {
	i := 1

	for {
		select {
		case <-time.Tick(500 * time.Millisecond):
			v := mydat{d: time.Now(), n: i}
			Add(vals, v)
			i++
			i = i % 10
		}
	}

}

// irregularScan processes the contents of the value ring at
// unpredictable times.
func irregularScan(vals ring.Ring) {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	for {
		select {
		case <-time.After(time.Duration(r.Intn(500)) * time.Millisecond):
			Scan(vals)
		}
	}

}

func main() {
	values := ring.New(ringSize)
	for i := 0; i < ringSize; i++ {
		values.Next().Value = mydat{d: time.Now(), n: 0}
	}

	go regularAdd(values)
	go irregularScan(values)

	time.Sleep(60 * time.Second)
	wg.Wait()
}
